home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 March: Reference Library / Dev.CD Mar 97 RL.toast / mac / Technical Documentation / develop / develop Issue 27 / develop Issue 27 code / Internet Config Assistant / InternetAssistant / HTMLParser.cp < prev    next >
Encoding:
Text File  |  1996-05-05  |  9.2 KB  |  431 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        HTMLParser.cp
  3.  
  4.     Contains:    A simplistic parse of a sub-set of HTML.
  5.                 Used to allow styles in dialogs.
  6.  
  7.     Written by:    Arno Gourdol
  8.  
  9.     Copyright:    © 1996 by Apple Computer, Inc., all rights reserved.
  10.  
  11. */
  12.  
  13. #include "HTMLParser.h"
  14. #include "assert.h"
  15. #include "macros.h"
  16.  
  17. #include <TextUtils.h>
  18.  
  19.  
  20.  
  21. // --------------------------------------------------------------------
  22. // HTMLParser
  23. // --------------------------------------------------------------------
  24.  
  25. HTMLParser::HTMLParser(Handle text, SInt32 fromIndex, SInt32 toIndex) :
  26.     fTextHandle(text),
  27.     fCursor(fromIndex - 1),
  28.     fFinalCursor(toIndex),
  29.     fContinue(true)
  30. {
  31.     assert(text != NULL);
  32.     assert(fromIndex >= 0);
  33.  
  34.     if (toIndex < 0)
  35.         fFinalCursor = ::GetHandleSize(text) - 1;
  36.         
  37.     fSavedHandleState = HGetState(fTextHandle);
  38.     HLock(fTextHandle);
  39.     fText = *fTextHandle;
  40. }
  41.  
  42.  
  43.  
  44. // --------------------------------------------------------------------
  45. // ~HTMLParser
  46. // --------------------------------------------------------------------
  47.  
  48. HTMLParser::~HTMLParser()
  49. {
  50.     HSetState(fTextHandle, fSavedHandleState);
  51. }
  52.  
  53.  
  54.  
  55. // --------------------------------------------------------------------
  56. // IsTag
  57. // --------------------------------------------------------------------
  58.  
  59. Boolean HTMLParser::IsTag(SInt32 tagStart, SInt32 tagEnd, 
  60.                         ConstStr255Param tag)
  61. {
  62. #pragma unused (tagStart)
  63. #pragma unused (tagEnd)
  64. #pragma unused (tag)
  65.     SInt16 result = IdenticalText(&fText[tagStart], &tag[1], 
  66.                                         tag[0] - 1, tag[0] - 1, NULL);
  67.     
  68.     // Furthermore, the next character must be white space or
  69.     // end of tag ???
  70.  
  71.     return (result == 0);
  72. }
  73.  
  74.  
  75.  
  76. // --------------------------------------------------------------------
  77. // Tag
  78. // --------------------------------------------------------------------
  79.  
  80. void HTMLParser::Tag(SInt32 tagStart, SInt32 tagEnd)
  81. {
  82.     if (IsTag(tagStart, tagEnd, "\p<B>"))
  83.     {
  84.         TagBoldStart(tagStart, tagEnd);
  85.     }
  86.     else if (IsTag(tagStart, tagEnd, "\p</B>"))
  87.     {
  88.         TagBoldEnd(tagStart, tagEnd);
  89.     }
  90.     else if (IsTag(tagStart, tagEnd, "\p<I>"))
  91.     {
  92.         TagItalicStart(tagStart, tagEnd);
  93.     }
  94.     else if (IsTag(tagStart, tagEnd, "\p</I>"))
  95.     {
  96.         TagItalicEnd(tagStart, tagEnd);
  97.     }
  98. }
  99.  
  100.  
  101.  
  102. // --------------------------------------------------------------------
  103. // TagBoldStart
  104. // --------------------------------------------------------------------
  105.  
  106. void HTMLParser::TagBoldStart(SInt32 tagStart, SInt32 tagEnd)
  107. {
  108. #pragma unused (tagStart)
  109. #pragma unused (tagEnd)
  110. }
  111.  
  112.  
  113.  
  114. // --------------------------------------------------------------------
  115. // TagBoldEnd
  116. // --------------------------------------------------------------------
  117.  
  118. void HTMLParser::TagBoldEnd(SInt32 tagStart, SInt32 tagEnd)
  119. {
  120. #pragma unused (tagStart)
  121. #pragma unused (tagEnd)
  122. }
  123.  
  124.  
  125.  
  126. // --------------------------------------------------------------------
  127. // TagItalicStart
  128. // --------------------------------------------------------------------
  129.  
  130. void HTMLParser::TagItalicStart(SInt32 tagStart, SInt32 tagEnd)
  131. {
  132. #pragma unused (tagStart)
  133. #pragma unused (tagEnd)
  134. }
  135.  
  136.  
  137.  
  138. // --------------------------------------------------------------------
  139. // TagItalicEnd
  140. // --------------------------------------------------------------------
  141.  
  142. void HTMLParser::TagItalicEnd(SInt32 tagStart, SInt32 tagEnd)
  143. {
  144. #pragma unused (tagStart)
  145. #pragma unused (tagEnd)
  146. }
  147.  
  148.  
  149.  
  150. // --------------------------------------------------------------------
  151. // EndOfText
  152. // --------------------------------------------------------------------
  153.  
  154. void HTMLParser::EndOfText(SInt32 endOfText)
  155. {
  156. #pragma unused (endOfText)
  157. }
  158.  
  159.  
  160.  
  161. // --------------------------------------------------------------------
  162. // Parse
  163. // --------------------------------------------------------------------
  164.  
  165. void HTMLParser::Parse(void)
  166. {
  167.     UInt16 c;
  168.     while (fContinue)
  169.     {
  170.         c = GetChar();
  171.         if (c == '<')
  172.         {
  173.             // Potential start of a tag
  174.             UInt32 startTag = GetCursor();
  175.             
  176.             UInt32 endTag = FindChar('>');
  177.             
  178.             if (endTag >= 0)
  179.             {
  180.                 Tag(startTag, endTag);
  181.                 SetCursor(endTag);
  182.             }
  183.         }
  184.     }
  185.     EndOfText(max(GetCursor(), GetFinalCursor()));
  186. }
  187.  
  188.  
  189.  
  190. // --------------------------------------------------------------------
  191. // SkipWhiteSpaces
  192. // --------------------------------------------------------------------
  193.  
  194. void HTMLParser::SkipWhiteSpaces(void)
  195. {
  196.     UInt16 c;
  197.  
  198.     do
  199.     {
  200.         c = GetChar();
  201.     } while (c == ' ');
  202.     // ??? Use Character type to catch all the white spaces
  203.     
  204.     // Roll back one if we have found white space
  205.     SetCursor(GetCursor() - 1);
  206. }
  207.  
  208.  
  209.  
  210. // --------------------------------------------------------------------
  211. // GetChar
  212. // --------------------------------------------------------------------
  213.  
  214. UInt16 HTMLParser::GetChar(void)
  215. {
  216.     if (GetCursor() >= GetFinalCursor())
  217.     {
  218.         Abort();
  219.         return 0;
  220.     }
  221.     else
  222.     {
  223.         Byte c;
  224.         // ??? Should use FillParseTable to take into account
  225.         // 2-bytes characters
  226.         c = fText[++fCursor];
  227.         return c;
  228.     }
  229. }
  230.  
  231.  
  232.  
  233. // --------------------------------------------------------------------
  234. // FindChar
  235. // --------------------------------------------------------------------
  236. //
  237. // Find a character in the text stream, return its index
  238. // -1 if not found
  239. // Do not change the cursor
  240.  
  241. SInt32 HTMLParser::FindChar(UInt16 c)
  242. {
  243.     SInt32 result;
  244.     SInt32 saveCursor = GetCursor();
  245.     
  246.     Byte currentChar;
  247.     
  248.     do
  249.     {
  250.         currentChar = GetChar();
  251.     } while (fContinue && currentChar != c);
  252.     
  253.     if (!fContinue)
  254.         result = -1;
  255.     else
  256.         result = GetCursor();
  257.     
  258.     SetCursor(saveCursor);
  259.     
  260.     return result;
  261. }
  262.  
  263.  
  264.  
  265. // --------------------------------------------------------------------
  266. // HTMLToStyledText
  267. // --------------------------------------------------------------------
  268.  
  269. HTMLToStyledText::HTMLToStyledText(CRect frame, Handle text) :
  270.     HTMLParser(text),
  271.     fFrame(frame),
  272.     fStyledText(NULL),
  273.     fLastTextStyleChange(0),
  274.     fBold(0),
  275.     fItalic(0)
  276. {
  277. //    fStyledText = TEStyleNew(fFrame, fFrame);
  278. }
  279.  
  280.  
  281.  
  282. // --------------------------------------------------------------------
  283. // GetStyledText
  284. // --------------------------------------------------------------------
  285.  
  286. TEHandle HTMLToStyledText::GetStyledText(void)
  287. {
  288.     return fStyledText;
  289. }
  290.  
  291.  
  292.  
  293. // --------------------------------------------------------------------
  294. // ApplyTextStyles
  295. // --------------------------------------------------------------------
  296.  
  297. void HTMLToStyledText::ApplyTextStyles(SInt32 upToIndex)
  298. {
  299.     assert(upToIndex >= -1 && upToIndex <= GetFinalCursor());
  300.     
  301.     if (fStyledText == NULL)
  302.     {
  303.         fStyledText = TEStyleNew(fFrame, fFrame);
  304.     }
  305.     
  306.     {
  307.         {
  308.             SInt32 endOfText = GetHandleSize((**fStyledText).hText);
  309.             
  310.             OSErr err = PtrAndHand(&fText[fLastTextStyleChange], 
  311.                         (**fStyledText).hText, 
  312.                         (upToIndex - fLastTextStyleChange) + 1);
  313.             assert(err == noErr);
  314.             
  315.             TESetSelect(endOfText, 32000, fStyledText);
  316.         }
  317.         {
  318.             TextStyle newStyle;
  319.             newStyle.tsFace = normal;
  320.             newStyle.filler = 0;        // Workaround for style
  321.                                         // TextEdit bug see TE.16
  322.             if (fBold > 0)
  323.                 newStyle.tsFace |= bold;
  324.             if (fItalic > 0)
  325.                 newStyle.tsFace |= italic;
  326.  
  327.             TESetStyle(doFace, &newStyle, false, fStyledText);
  328.         }
  329.     }
  330. }
  331.  
  332.  
  333.  
  334. // --------------------------------------------------------------------
  335. // TagBoldStart
  336. // --------------------------------------------------------------------
  337.  
  338. void HTMLToStyledText::TagBoldStart(SInt32 tagStart, SInt32 tagEnd)
  339. {
  340.     ApplyTextStyles(tagStart - 1);
  341.     fLastTextStyleChange = tagEnd + 1;
  342.     fBold++;
  343. }
  344.  
  345.  
  346.  
  347. // --------------------------------------------------------------------
  348. // TagBoldEnd
  349. // --------------------------------------------------------------------
  350.  
  351. void HTMLToStyledText::TagBoldEnd(SInt32 tagStart, SInt32 tagEnd)
  352. {
  353.     ApplyTextStyles(tagStart - 1);
  354.     fLastTextStyleChange = tagEnd + 1;
  355.     fBold--;
  356. }
  357.  
  358.  
  359.  
  360. // --------------------------------------------------------------------
  361. // TagItalicStart
  362. // --------------------------------------------------------------------
  363.  
  364. void HTMLToStyledText::TagItalicStart(SInt32 tagStart, SInt32 tagEnd)
  365. {
  366.     ApplyTextStyles(tagStart - 1);
  367.     fLastTextStyleChange = tagEnd + 1;
  368.     fItalic++;
  369. }
  370.  
  371.  
  372.  
  373. // --------------------------------------------------------------------
  374. // TagItalicEnd
  375. // --------------------------------------------------------------------
  376.  
  377. void HTMLToStyledText::TagItalicEnd(SInt32 tagStart, SInt32 tagEnd)
  378. {
  379.     ApplyTextStyles(tagStart - 1);
  380.     fLastTextStyleChange = tagEnd + 1;
  381.     fItalic--;
  382. }
  383.  
  384.  
  385.  
  386. // --------------------------------------------------------------------
  387. // EndOfText
  388. // --------------------------------------------------------------------
  389. //
  390. // endOfText is the index to the last character
  391.  
  392. void HTMLToStyledText::EndOfText(SInt32 endOfText)
  393. {
  394.     if (fStyledText != NULL)
  395.     {
  396.         ApplyTextStyles(endOfText);
  397.         TESetSelect(GetHandleSize((**fStyledText).hText) - 1, 
  398.                     GetHandleSize((**fStyledText).hText), fStyledText);
  399.         {
  400.             TextStyle newStyle;
  401.             newStyle.tsFace = bold;
  402.             newStyle.filler = 0;        // Workaround for style
  403.                                         // TextEdit bug see TE.16
  404.             TESetStyle(doFace, &newStyle, false, fStyledText);
  405.         }
  406.         TECalText(fStyledText);
  407.     }
  408. }
  409.  
  410.  
  411.  
  412. // --------------------------------------------------------------------
  413. // ConvertHTMLToStyledText
  414. // --------------------------------------------------------------------
  415. // Parses "text". If it contains HTML tags, create a new TextEdit 
  416. // record with all the styles set appropriately.
  417. // Returns NULL otherwise.
  418.  
  419. void ConvertHTMLToStyledText(Handle text, CRect frame, 
  420.                                                     TEHandle* textEdit)
  421. {
  422.     HTMLToStyledText parser(frame, text);
  423.         
  424.     parser.Parse();
  425.  
  426.     *textEdit = parser.GetStyledText();
  427. }
  428.  
  429.  
  430.  
  431.